#ifndef __IM_LOOKUP_TABLE_H__
#define __IM_LOOKUP_TABLE_H__

#include <im_base_types.h>
#include <im_object.h>
#include <im_text.h>
#include <im_string.h>

/**
 * @defgroup IMLookupTable IMLookupTable and IMCandidate
 * @ingroup PublicIME
 * @{
 */

/**
 * @struct IMCandidate
 * @brief IMCandidate class is used to hold necessary data of a candidate phrase
 *        which can be put into an IMLookupTable object and displayed by GUI
 *        component.
 *
 * IMCandidate class shall consist the following kinds of data members of a candidate phrase.
 * - Label
 *   type: IMText
 *   A text label to indicate the candidate on lookup table.
 * - Content
 *   type: IMText
 *   Content of the candidate on lookup table. If the content is empty, UIC may
 *   refuse to render the this item, it depends on the UIC implementation.
 * - Icon
 *   type: IMString
 *   The identifier (usually a path name) of an icon that UIC may display
 *   along with the candidate content.
 * - Annotation
 *   type: IMObject
 *   An object to annotate the candidate.
 *   If it's an IMText object, then it maybe a description of the candidate.
 *   If it's an IMLookupTable object, then it's a sub lookup table associated
 *   with the candidate.
 *   Default GUI component may only recognize and handle IMText or IMLookupTable
 *   annotations.
 *
 * These data members can only be accessed by setter and getter interfaces of
 * IMCandidate object. The default values of these data members are null.
 */

/**
 * @struct IMLookupTable
 * @brief IMLookupTable class is used to manipulate a set of IMCandidate objects.
 *
 * Only one page of candidates can be stored in an IMLookupTable object.
 *
 * Only one candidate can be focused at one time, it's specified by the cursor
 * position. Only the annotation of focused candidate will be displayed.
 *
 * A lookup table is a two dimension table, table size (X and Y) and orientation
 * is specified by caller. The origin is upper left corner. Candidate index starts
 * from zero. A scroll bar can be available. Necessary data to show the scroll bar
 * is provided by caller, such as number of pages and current page.
 * A title can be specified by caller.
 *
 * For example for a 4 x 3 table:
 *
 * @code
 * Horizontal table:           Vertical table:
 *
 * [ Title ]                   [ Title ]
 * +----+----+----+----+       +----+----+----+----+ A
 * | 0  | 1  | 2  | 3  |       | 0  | 3  | 6  | 9  | |
 * +----+----+----+----+       +----+----+----+----+ |
 * | 4  | 5  | 6  | 7  |       | 1  | 4  | 7  | 10 | =
 * +----+----+----+----+       +----+----+----+----+ |
 * | 8  | 9  | 10 | 11 |       | 2  | 5  | 8  | 11 | |
 * +----+----+----+----+       +----+----+----+----+ V
 * <----[]------------->
 * @endcode
 *
 * In the case of multi-level lookup table, the second level
 * lookup tables are associated with corresponding candidates
 * in the first level lookup table.
 *
 * For example, the 2nd level lookup table is associated with
 * the No. 6 candidate in the first level:
 *
 * @code
 * Multi-level lookup table:
 *
 * [ Title 1 ]
 * +----+----+----+----+
 * | 0  | 1  | 2  | 3  |
 * +----+----+----+----+
 * | 4  | 5  | 6 -+----+--> [ Title 2 ]
 * +----+----+----+----+    +----+----+----+
 * | 8  | 9  | 10 | 11 |    | 0  | 1  | 2  |
 * +----+----+----+----+    +----+----+----+
 * <----[]------------->    | 3  | 4  | 5  |
 *                          +----+----+----+
 *                          <----[]-------->
 * @endcode
 *
 */

IM_BEGIN_DECLS

/** @brief the maximum number of columns */
#define IM_LOOKUP_TABLE_MAX_N_COLUMNS   256
/** @brief the maximum number of rows */
#define IM_LOOKUP_TABLE_MAX_N_ROWS      256

/** @brief cast the pointer to IMCandidate*, return NULL if failed. */
#define IM_CANDIDATE(p)                 (IM_TYPE_INSTANCE_CHECK_CAST((p),IM_TYPE_CANDIDATE,IMCandidate))
/** @brief cast the pointer to const IMCandidate*, return NULL if failed. */
#define IM_CONST_CANDIDATE(p)           (IM_TYPE_INSTANCE_CHECK_CAST_CONST((p),IM_TYPE_CANDIDATE,IMCandidate))
/** @brief cast the pointer to IMCandidateClass*, return NULL if failed. */
#define IM_CANDIDATE_CLASS(c)           (IM_TYPE_CLASS_CHECK_CAST((c),IM_TYPE_CANDIDATE,IMCandidateClass))
/** @brief tell if the pointer is an instance of IMCandidate */
#define IM_IS_CANDIDATE(p)              (IM_TYPE_INSTANCE_CHECK_TYPE((p),IM_TYPE_CANDIDATE))
/** @brief tell if the pointer is an IMCandidateClass */
#define IM_IS_CANDIDATE_CLASS(c)        (IM_TYPE_CLASS_CHECK_TYPE((c),IM_TYPE_CANDIDATE))
/** @brief get the IMCandidateClass from an instance of IMCandidate */
#define IM_CANDIDATE_GET_CLASS(p)       (IM_TYPE_INSTANCE_GET_CLASS_CAST((p),IM_TYPE_CANDIDATE,IMCandidateClass))

/** @brief cast the pointer to IMLookupTable*, return NULL if failed. */
#define IM_LOOKUP_TABLE(p)              (IM_TYPE_INSTANCE_CHECK_CAST((p),IM_TYPE_LOOKUP_TABLE,IMLookupTable))
/** @brief cast the pointer to const IMLookupTable*, return NULL if failed. */
#define IM_CONST_LOOKUP_TABLE(p)        (IM_TYPE_INSTANCE_CHECK_CAST_CONST((p),IM_TYPE_LOOKUP_TABLE,IMLookupTable))
/** @brief cast the pointer to IMLookupTableClass*, return NULL if failed. */
#define IM_LOOKUP_TABLE_CLASS(c)        (IM_TYPE_CLASS_CHECK_CAST((c),IM_TYPE_LOOKUP_TABLE,IMLookupTableClass))
/** @brief tell if the pointer is an instance of IMLookupTable */
#define IM_IS_LOOKUP_TABLE(p)           (IM_TYPE_INSTANCE_CHECK_TYPE((p),IM_TYPE_LOOKUP_TABLE))
/** @brief tell if the pointer is an IMLookupTableClass */
#define IM_IS_LOOKUP_TABLE_CLASS(c)     (IM_TYPE_CLASS_CHECK_TYPE((c),IM_TYPE_LOOKUP_TABLE))
/** @brief get the IMLookupTableClass from an instance of IMLookupTable */
#define IM_LOOKUP_TABLE_GET_CLASS(p)    (IM_TYPE_INSTANCE_GET_CLASS_CAST((p),IM_TYPE_LOOKUP_TABLE,IMLookupTableClass))

typedef struct _IMCandidate             IMCandidate;
typedef struct _IMCandidateClass        IMCandidateClass;

typedef struct _IMLookupTable           IMLookupTable;
typedef struct _IMLookupTableClass      IMLookupTableClass;

/**
 * @enum IMLookupTableOrientation
 * @brief Layout orientation of a lookup table.
 * - IM_LOOKUP_TABLE_LTRTTB
 *   the layout orientation is from left to right, top to bottom.
 * - IM_LOOKUP_TABLE_RTLTTB
 *   the layout orientation is from right to left, top to bottom.
 * - IM_LOOKUP_TABLE_TTBLTR
 *   the layout orientation is from top to bottom, left to right.
 * - IM_LOOKUP_TABLE_TTBRTL
 *   the layout orientation is from top to bottom, right to left.
 */
typedef enum {
    IM_LOOKUP_TABLE_LTRTTB = 0,
    IM_LOOKUP_TABLE_RTLTTB = 1,
    IM_LOOKUP_TABLE_TTBLTR = 2,
    IM_LOOKUP_TABLE_TTBRTL = 3
} IMLookupTableOrientation;

/**
 * @enum IMLookupTableFlag
 * @brief Flags to control various behaviour of a lookup table.
 *
 * A flag can be set to TRUE or FALSE
 * - IM_LOOKUP_TABLE_SHOW_TITLE
 *   Whether to show title text or not, default not show.
 * - IM_LOOKUP_TABLE_SHOW_CURSOR
 *   Whether to show cursor or not, default show.
 * - IM_LOOKUP_TABLE_SHOW_SCROLL_BAR
 *   Whether to show scroll bar or not, default not show.
 * - IM_LOOKUP_TABLE_SHOW_PAGE_FLIP_BUTTONS
 *   Whether to show page flip buttons (page up and page down) or not,
 *   default show.
 * - IM_LOOKUP_TABLE_HORIZONTAL_SHRINKABLE
 *   Whether the page size can be shrunk by GUI component in
 *   horizontal orientation or not, default not shrinkable.
 *   If it's shrinkable and the size is shrunk by GUI component,
 *   an event will be sent back to IMEngine to indicate it.
 * - IM_LOOKUP_TABLE_VERTICAL_SHRINKABLE
 *   Whether the page size can be shrunk by GUI component in
 *   vertical orientation or not, default not shrinkable.
 *   If it's shrinkable and the size is shrunk by GUI component,
 *   an event will be sent back to IMEngine to indicate it.
 */
typedef enum {
    IM_LOOKUP_TABLE_SHOW_TITLE = 0,
    IM_LOOKUP_TABLE_SHOW_CURSOR,
    IM_LOOKUP_TABLE_SHOW_SCROLL_BAR,
    IM_LOOKUP_TABLE_SHOW_PAGE_FLIP_BUTTONS,
    IM_LOOKUP_TABLE_HORIZONTAL_SHRINKABLE,
    IM_LOOKUP_TABLE_VERTICAL_SHRINKABLE
} IMLookupTableFlag;

/**
 * @brief   Creates a new IMCandidate with specified content.
 *
 *
 * @param   content     an IMText of the candidate's content. The content object
 *                      will only be referenced rather than cloned.
 *
 * @return  a new IMCandidate.
 */
IMCandidate*    im_candidate_new                (IMText                 *content);

/**
 * @brief   Creates a new IMCandidate with specified content, label, icon and
 *          annotation.
 *
 * @param   content     an IMText of the candidate's content.
 * @param   label       an IMText of the candidate's label.
 * @param   icon        an IMText of the candidate's icon.
 * @param   annotation  an IMPointer of annotation data for the candidate.
 *
 * The objects in parameter list will only be referenced rather than cloned.
 *
 * @return  a new IMCandidate.
 */
IMCandidate*    im_candidate_new_full           (IMText                 *content,
                                                 IMText                 *label,
                                                 IMString               *icon,
                                                 IMPointer               annotation);

/**
 * @brief   Sets the content of an IMCandidate.
 *
 * @param   candidate   an IMCandidate.
 * @param   content     the new content for candidate.
 *
 * The content object will only be referenced rather than cloned.
 */
void            im_candidate_set_content        (IMCandidate            *candidate,
                                                 IMText                 *content);

/**
 * @brief   Gets the content of an IMCandidate.
 *
 * @param   candidate   an IMCandidate.
 *
 * @return  the candidate's content, that you should not free.
 */
IMText*         im_candidate_get_content        (const IMCandidate      *candidate);

/**
 * @brief   Sets the label of an IMCandidate.
 *
 * @param   candidate   an IMCandidate.
 * @param   label       the new label for candidate.
 *
 * The label object will only be referenced rather than cloned.
 */
void            im_candidate_set_label          (IMCandidate            *candidate,
                                                 IMText                 *label);
/**
 * @brief   Gets the label of an IMCandidate.
 *
 * @param   candidate   an IMCandidate.
 *
 * @return  the candidate's label, that you should not free.
 */
IMText*         im_candidate_get_label          (const IMCandidate      *candidate);

/**
 * @brief   Sets the icon file path of an IMCandidate.
 *
 * @param   candidate   an IMCandidate.
 * @param   icon        the new icon file path for candidate.
 *
 * The icon identifier object will only be referenced rather than cloned.
 */
void            im_candidate_set_icon           (IMCandidate            *candidate,
                                                 IMString               *icon);

/**
 * @brief   Gets the icon file path of an IMCandidate.
 *
 * @param   candidate   an IMCandidate.
 *
 * @return  the candidate's icon file path, that you should not free.
 */
IMString*       im_candidate_get_icon           (const IMCandidate      *candidate);

/**
 * @brief   Sets the annotation data of an IMCandidate.
 *
 * @param   candidate   an IMCandidate.
 * @param   annotation  the new annotation data for candidate.
 *
 * The annotation object will only be referenced rather than cloned.
 */
void            im_candidate_set_annotation     (IMCandidate            *candidate,
                                                 IMPointer              *annotation);

/**
 * @brief   Gets the annotation data of an IMCandidate.
 *
 * @param   candidate   an IMCandidate.
 *
 * @return  the candidate's annotation data, that you should not free.
 */
IMPointer       im_candidate_get_annotation     (const IMCandidate      *candidate);

/**
 * @brief   Creates a new empty IMLookupTable.
 *
 * Each IMLookupTable has an integer ID to identify itself.
 * This allows an IMEngine to use multiple IMLookupTables
 * at the same time. It is useful for multi-level lookup table
 * case: candidates in a lookup table have other lookup table
 * objects as their annotations.
 *
 * @param   id  an integer ID to identify this IMLookupTable.
 *
 * @return  a new IMLookupTable.
 */
IMLookupTable*  im_lookup_table_new             (IMUInt32                id);

/**
 * @brief   Creates a new empty IMLookupTable.
 * @see     im_lookup_table_new()
 *
 * @param   id              an integer ID to identify this IMLookupTable.
 * @param   orientation     the orientation of the IMLookupTable.
 * @param   cols            number of columns in the lookup table.
 * @param   rows            number of rows in the lookup table.
 * @param   flags           An array contains all flags that need to be set to
 *                          TRUE.
 * @param   n_flags         Number of flags in flags array.
 *
 * @return  a new IMLookupTable.
 */
IMLookupTable*  im_lookup_table_new_full        (IMUInt32                id,
                                                 IMUInt                  orientation,
                                                 IMUInt                  cols,
                                                 IMUInt                  rows,
                                                 IMLookupTableFlag      *flags,
                                                 IMSize                  n_flags);

/**
 * @brief   Clears the content of an IMLookupTable.
 *
 * Only title, candidates, labels and annotations will be cleared.
 * Other information won't be changed.
 *
 * @param   table   an IMLookupTable.
 */
void            im_lookup_table_clear           (IMLookupTable          *table);

/**
 * @brief   Sets the ID of an IMLookupTable.
 *
 * @param   table   Pointer to an IMLookupTable object.
 * @param   id      A new integer ID to be used.
 */
void            im_lookup_table_set_id          (IMLookupTable          *table,
                                                 IMUInt32                id);

/**
 * @brief   Gets the ID of an IMLookupTable.
 *
 * @param   table   Pointer to an IMLookupTable object.
 *
 * @return  Integer ID of the specified IMLookupTable object.
 */
IMUInt32        im_lookup_table_get_id          (const IMLookupTable    *table);

/**
 * @brief   Sets the layout orientation of an IMLookupTable.
 *
 * @param   table       Pointer to an IMLookupTable object.
 * @param   orientation One of the values defined in IMLookupTableOrientation.
 */
void            im_lookup_table_set_orientation (IMLookupTable          *table,
                                                 IMLookupTableOrientation orientation);

/**
 * @brief   Gets the layout orientation of an IMLookupTable.
 *
 * @param   table   Pointer to an IMLookupTable object.
 *
 * @return  the layout orientation.
 */
IMLookupTableOrientation im_lookup_table_get_orientation (const IMLookupTable    *table);

/**
 * @brief   Sets the IMLookupTable's page size
 *
 * A lookup table is a two dimension table, which can have multiple columns and
 * rows. The total number of candidates can be hold by a table is
 * number_of_columns * number_of_rows.
 * Candidates can be indexed by linear numbers from * 0 to (ncols * nrows - 1).
 * The layout orientation of candidates is specified by caller.
 *
 * @param   table   Pointer to an IMLookupTable object.
 * @param   cols    number of columns (X size), must be greater than
 *                  zero and less equal than IM_LOOKUP_TABLE_MAX_N_COLUMNS.
 * @param   rows    number of rows (Y size), must be greater than zero
 *                  and less equal than IM_LOOKUP_TABLE_MAX_N_ROWS.
 */
void            im_lookup_table_set_page_size   (IMLookupTable          *table,
                                                 IMUInt                  cols,
                                                 IMUInt                  rows);
/**
 * @brief Get lookup table's page size
 *
 * @param table     Pointer to an IMLookupTable object.
 * @param cols      number of columns (X size).
 * @param rows      number of rows (Y size).
 */
void            im_lookup_table_get_page_size   (const IMLookupTable    *table,
                                                 IMUInt                 *cols,
                                                 IMUInt                 *rows);
/**
 * @brief Set cursor position (the currently focused candidate)
 *        in current page.
 *
 * @param table     Pointer to an IMLookupTable object.
 * @param cur       the cursor index in that table, if beyonds the last element,
 *                  it will be set to the end (i.e. columns*rows - 1).
 */
void            im_lookup_table_set_cursor      (IMLookupTable          *table,
                                                 IMUInt                  cur);

/**
 * @brief Get cursor position (the currently focused candidate).
 *
 * @param table     Pointer to an IMLookupTable object.
 *
 * @return          the cursor index.
 */
IMUInt          im_lookup_table_get_curosr      (const IMLookupTable    *table);

/**
 * @brief Enable or disable a specified flag for a lookup table to adjust its
 * behaviour.
 *
 * @param table     Pointer to an IMLookupTable object.
 * @param flag      A flag to be enabled or disabled.
 * @param state     If it's TRUE then the specified flag will be enabled.
 */
void            im_lookup_table_set_flag        (IMLookupTable          *table,
                                                 IMLookupTableFlag       flag,
                                                 IMBool                  state);
/**
 * @brief Check the status of a specified flag of an IMLookupTable object.
 *
 * @param table     Pointer to an IMLookupTable object.
 * @param flags     the flag to be checked.
 *
 * @return Returns TRUE if the specified flag is enabled for the specified
 * IMLookupTable object.
 */
IMBool          im_lookup_table_check_flag      (const IMLookupTable    *table,
                                                 IMLookupTableFlag       flag);
/**
 * @brief Set title of a lookup table.
 *
 * @param table     an IMLookupTable.
 * @param title     an IMText object, which can have text attributes to decorate the text.
 */
void            im_lookup_table_set_title       (IMLookupTable          *table,
                                                 IMText                 *title);
/**
 * @brief Get title of a lookup table.
 *
 * @param table     an IMLookupTable.
 *
 * @return The IMText object used by the lookup table object as title,
 *         0 if there is no title. It shouldn't be modified or released
 *         by caller.
 */
IMText*         im_lookup_table_get_title       (const IMLookupTable    *table);

/**
 * @brief Set scroll bar information of a lookup table.
 *
 * A lookup table can have a scroll bar to indicate which page is currently
 * displayed among all pages.
 * The scroll bar is also clickable by user to generate page flip event.
 *
 * @param table     an IMLookupTable object
 * @param num_pages Number of pages totally available.
 * @param cur_page  Current page is being displayed,
 *        must between 0 to (num_pages - 1).
 *        If it's 0, then the scroll bar cursor will be at beginning
 *        position, and the page up button will be inactivated,
 *        so that user can't do page up.
 *        If it's num_pages - 1, then the scroll bar cursor will be at
 *        ending position, and the page down button will be inactivated,
 *        so that user can't do page down.
 */
void            im_lookup_table_set_scroll_info (IMLookupTable          *table,
                                                 IMUInt                  num_pages,
                                                 IMUInt                  cur_page);

/**
 * @brief Get scroll bar information of a lookup table.
 *
 * @param table     an IMLookupTable object
 * @param num_pages Number of pages totally available.
 * @param cur_page  Current page is being displayed,
 */
void            im_lookup_table_get_scroll_info (const IMLookupTable    *table,
                                                 IMUInt                 *num_pages,
                                                 IMUInt                 *cur_page);

/**
 * @brief Set the candidate at specified index.
 *
 * @param table an IMLookupTable object
 * @param index candidate index to be set. Must be 0 to (page_size - 1).
 *              page_size = cols * rows.
 * @param cand  an IMCandidate object.
 */
void            im_lookup_table_set_candidate   (IMLookupTable          *table,
                                                 IMUInt                  index,
                                                 IMCandidate            *candidate);
/**
 * @brief Get the candidate at specified index.
 *
 * @param table     an IMLookupTable object
 * @param index     candidate index to be get. Must be 0 to (page_size - 1).
 *                  page_size = cols * rows.
 * @return The IMCandidate object. Or 0 if the candidate is empty.
 */
IMCandidate*    im_lookup_table_get_candidate   (const IMLookupTable    *table,
                                                 IMUInt                  index);
IM_END_DECLS

#endif
/** @} */
/*
vi:ts=4:nowrap:ai:expandtab
*/
